using System;
using System.Data;
using System.Reflection;

namespace FreeFlow.Administration
{
	/// <summary>
	/// A variable in a map.
	/// </summary>
  public class Column : DatabaseAware, IDeletable, IComparable<Column>
	{
    private string mapTableName;
    internal Column(Server server, IDataReader reader, int index, string mapTableName)
      : base(server)
		{
      name = reader.GetName(index);
      object val = reader.GetFieldType(index);
      Type runtimeType = val.GetType();
      PropertyInfo propInfo = runtimeType.GetProperty("UnderlyingSystemType");
      type = (Type)propInfo.GetValue(val, null);
      databaseType = reader.GetDataTypeName(index);
      DataTable schemaTable = reader.GetSchemaTable();
      size = (int)schemaTable.Rows[index]["ColumnSize"];
      this.mapTableName = mapTableName;
		}

    internal string ConstraintName
    {
      get
      {
        return string.Format("eConstraint{0}{1}", mapTableName, name);
      }
    }

    internal bool ConstraintExists(IDbTransaction transaction)
    {
      int count = (int)Server.ExecuteScalar(transaction, 
        string.Format("SELECT COUNT(*) FROM sysobjects WHERE name = '{0}'", ConstraintName));
      return (count > 0);
    }

    private string name;
    /// <summary>
    /// Gets the name of the variable.
    /// </summary>
    public string Name
    {
      get
      {
        return name;
      }
    }

    private Type type;
    /// <summary>
    /// Gets the .NET type of the variable.
    /// </summary>
    public Type Type
    {
      get
      {
        return type;
      }
    }

    private string databaseType;
    /// <summary>
    /// Gets the database type of the variable.
    /// </summary>
    public string DatabaseType
    {
      get
      {
        return databaseType;
      }
    }

    private int size;
    /// <summary>
    /// Gets the size of the variable.
    /// </summary>
    public int Size
    {
      get
      {
        return size;
      }
    }

    #region IDeletable Members

    bool deleted;
    /// <summary>
    /// Deletes this variable from the database.
    /// </summary>
    public void Delete()
    {
      if (!deleted)
      {
        using (IDbTransaction transaction = Server.BeginTransaction())
        {
          // SQL Server
          if (Server.DatabaseType == FreeFlow.Administration.DatabaseType.SqlServer)
          {
            // drop any constraints for the column
            if (ConstraintExists(transaction))
              Server.ExecuteNonQuery(transaction, string.Format("ALTER TABLE {0} DROP CONSTRAINT {1}", mapTableName, ConstraintName));
          }

          Server.ExecuteNonQuery(transaction,
            string.Format("ALTER TABLE {0} DROP COLUMN {1}", mapTableName, name));
         
          transaction.Commit();
        }
      }
      deleted = true;
    }

    #endregion

    #region IComparable<Variable> Members

    /// <summary>
    /// Compares the current object with another object of the same type.
    /// </summary>
    /// <param name="other">An object to compare with this object.</param>
    /// <returns>
    /// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other"/> parameter.Zero This object is equal to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
    /// </returns>
    public int CompareTo(Column other)
    {
      return string.Compare(Name, other.Name);
    }

    #endregion
  }
}
